package com.gzsxy.esjy.service.core.sign.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gzsxy.esjy.common.base.exception.impl.BusinessException;
import com.gzsxy.esjy.common.base.exception.impl.CustomAssert;
import com.gzsxy.esjy.feign.NettyFile.FileService;
import com.gzsxy.esjy.service.base.DictionaryConstants;
import com.gzsxy.esjy.service.core.sign.dao.ArraignSignMapper;
import com.gzsxy.esjy.service.core.sign.dao.ElectronicSealMapper;
import com.gzsxy.esjy.service.core.sign.dao.SignMapper;
import com.gzsxy.esjy.service.core.sign.dto.DocumentSignDto;
import com.gzsxy.esjy.service.core.sign.entity.ArraignSign;
import com.gzsxy.esjy.service.core.sign.entity.ElectronicSeal;
import com.gzsxy.esjy.service.core.sign.handler.SignHandlerCmd;
import com.gzsxy.esjy.service.core.sign.service.SignService;
import com.gzsxy.esjy.service.core.sign.service.doc.DocHandleService;
import com.gzsxy.esjy.service.core.util.SignFlowUtil;
import com.gzsxy.esjy.sign.dto.BaseSignProtocolDto;
import com.gzsxy.esjy.sign.service.GSSignBusinessService;
import com.gzsxy.esjy.sign.service.GSSignService;
import com.gzsxy.esjy.sign.util.SignProtocolUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.UUID;

@Service
public class SignServiceImpl extends ServiceImpl<SignMapper, ArraignSign> implements SignService {


    @Autowired
    private SignMapper signMapper;

    @Autowired
    private ElectronicSealMapper electronicSealMapper;

    @Autowired
    private FileService fileService;

    @Value("${local.ip:}")
    private String pathIp;

    @Autowired
    private DocHandleService docHandleService;


    @Autowired
    private ArraignSignMapper arraignSignMapper;


    @Autowired
    private GSSignBusinessService gsSignBusinessService;

    @Autowired
    private GSSignService gsSignService;


    /**
     * 文书盖章
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ArraignSign documentSeal(DocumentSignDto dto) {

        ArraignSign arraignSign = signMapper.selectById(dto.getId());
        CustomAssert.notTrue(null != arraignSign,"当前文件无签名记录");

        LambdaQueryWrapper<ElectronicSeal> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ElectronicSeal::getOrgCode,dto.getOrgCode())
                .eq(ElectronicSeal::getSealType,arraignSign.getType());
        ElectronicSeal electronicSeal = electronicSealMapper.selectOne(wrapper);
        CustomAssert.notTrue(null != electronicSeal,"所在部门未上传电子公章信息");

        //下载签章文件
        File electronicSealFile = null;
        try {
            int index = electronicSeal.getFileIndex().lastIndexOf(".");
            String sealFileType = electronicSeal.getFileIndex().substring(index);
            String electronicSealPath = String.format("%s/seal/%s%s", DictionaryConstants.PDF_TEMP_PATH, UUID.randomUUID().toString(), sealFileType);
            electronicSealFile = new File(electronicSealPath);
            downloadFile(electronicSeal.getFileIndex(),electronicSealFile);

            //保存pdf文件
            index = arraignSign.getLatestFile().lastIndexOf(".");
            String pdfFileType = arraignSign.getLatestFile().substring(index);
            String pdfFilePath = String.format("%s/seal/%s%s", DictionaryConstants.PDF_TEMP_PATH, UUID.randomUUID().toString(), pdfFileType);
            File pdfFile = new File(pdfFilePath);
            //获取未盖章文件路径，进行下载
            String signFile = SignFlowUtil.getSignFile(arraignSign, dto.getStepCode());
            downloadSignFile(signFile,pdfFile);
            //盖章
            docHandleService.doSeal(arraignSign,dto,electronicSealPath,pdfFile,pdfFileType);
            arraignSignMapper.updateById(arraignSign);
        } catch (Exception e) {
            throw BusinessException.getInstance(e.getMessage());
        } finally {
            //删除盖章本地临时文件
            electronicSealFile.delete();
        }
        return arraignSign;
    }

    /**
     * 文书添加日期
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ArraignSign documentDate(DocumentSignDto dto) {
        ArraignSign arraignSign = signMapper.selectById(dto.getId());
        CustomAssert.notTrue(null != arraignSign,"当前文件无签名记录");
        File pdfFile = null;
        //保存pdf文件
        try {
            int index = arraignSign.getLatestFile().lastIndexOf(".");
            String sealFileType = arraignSign.getLatestFile().substring(index);
            String pdfFilePath = String.format("%s/seal/%s%s", DictionaryConstants.PDF_TEMP_PATH, UUID.randomUUID().toString(), sealFileType);
            pdfFile = new File(pdfFilePath);
            //获取未添加日期文件路径，进行下载
            String signFile = SignFlowUtil.getSignFile(arraignSign, dto.getStepCode());
            //下载文书
            downloadSignFile(signFile,pdfFile);
            //统一进行添加日期
            docHandleService.doSign(arraignSign,null,null, DateUtil.now(),pdfFile,sealFileType);

            arraignSignMapper.updateById(arraignSign);
        } catch (Exception e) {
            throw BusinessException.getInstance(e.getMessage());
        } finally {
            pdfFile.delete();
        }
        return arraignSign;
    }




    /**
     * 下载盖章文件
     * @param url 文件url
     * @param file 本地保存文件
     */
    private void downloadFile(String url,File file){
        try {
            byte[] bytes = fileService.downloadFile(url);
            FileUtil.writeBytes(bytes,file);
        } catch (Exception e) {
            log.warn("盖章文件下载失败："+e.getMessage());
            throw BusinessException.getInstance("请管理员上传电子盖章后,再重新盖章");
        }
    }

    /**
     * 下载文书
     * @param url 文件url
     * @param file 本地保存文件
     */
    private void downloadSignFile(String url,File file){
        try {
//            String fileHttpPath = getFileHttpPath(url);
//            byte[] bytes = HttpUtil.downloadBytes(fileHttpPath);
            byte[] bytes = fileService.downloadFile(url);
            FileUtil.writeBytes(bytes,file);
        } catch (Exception e) {
            log.warn("文书下载失败："+e.getMessage());
            throw BusinessException.getInstance("文书下载失败");
        }

    }


    /**
     * 获取http访问地址
     * @param filePath 文件路径
     * @return http
     */
    private String getFileHttpPath(String filePath){
        //这种方式是通过nginx找到网关ip+端口/file-server再进行转发到下层服务
//        return String.format("http://%s/file-server/resources/%s",this.pathIp,filePath);
        return String.format("http://%s:%s/resources/%s","127.0.0.1","8098",filePath);
    }


    /**
     * 文书签名
     * @param documentSignDto
     */
    @Override
    public void documentSign(DocumentSignDto documentSignDto) {
        ArraignSign arraignSign = signMapper.selectById(documentSignDto.getId());
        CustomAssert.notTrue(null != arraignSign,"当前文件无签名记录");
        String requestId = this.getRequestId(SignHandlerCmd.DOCUMENT,arraignSign.getId(),documentSignDto.getSignUserType());
        //获取未添加日期文件路径，进行下载
        String signFile = SignFlowUtil.getSignFile(arraignSign, documentSignDto.getStepCode());
        String pdfHttpPath = getFileHttpPath(signFile);
        //封装对应设备类型协议体
        BaseSignProtocolDto signProtocol = SignProtocolUtil.getSignByType(requestId, documentSignDto.getSignDev().getSignDevType(), pdfHttpPath,
                gsSignBusinessService.getUploadPdfUrl(requestId), gsSignBusinessService.getSignOkUrl());
        //发起签名
        gsSignService.sign(documentSignDto.getSignDev().getIp(),documentSignDto.getSignDev().getPort(),signProtocol);
    }



    /**
     * 组装请求ID
     * @param signHandler
     * @param id
     * @param signUserType
     * @return
     */
    private String getRequestId(String signHandler,String id,String signUserType){
        //处理handler-签名用户类型-签名用户账号-业务ID
        return String.join(",",signHandler,signUserType,id);
    }


    /**
     * 文书取消签名
     * @param documentSignDto
     */
    @Override
    public void documentCancelSign(DocumentSignDto documentSignDto) {
        ArraignSign arraignSign = arraignSignMapper.selectById(documentSignDto.getId());
        CustomAssert.isBlank(arraignSign,"签名记录不存在");
        String requestId = this.getRequestId(SignHandlerCmd.DOCUMENT,arraignSign.getId(),documentSignDto.getSignUserType());
        Integer signDevType = documentSignDto.getSignDev().getSignDevType();
        BaseSignProtocolDto signProtocol = SignProtocolUtil.getCancelSignByType(requestId, signDevType, gsSignBusinessService.getSignOkUrl());
        gsSignService.cancelSign(documentSignDto.getSignDev().getIp(),documentSignDto.getSignDev().getPort(),signProtocol);
    }

}
